#pragma once
#include <QString>
#include <QIcon>
#include <QUuid>
#include <QDateTime>
#include <QPixmap>
#include <QFile>
#include <QDebug>
#include <QFileInfo>

#include "base.qpb.h"
#include "gateway.qpb.h"
#include "user.qpb.h"
#include "friend.qpb.h"
#include "file.qpb.h"
#include "notify.qpb.h"
#include "speech_recognition.qpb.h"
#include "message_storage.qpb.h"
#include "message_transmit.qpb.h"

namespace model {
/***
*工具函数
***/
// 获取文件名
static inline QString getFileName(const QString path){
    QFileInfo fileinfo(path);
    return fileinfo.fileName();
}

// 打印日志信息
#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))
#define  LOG() qDebug().noquote() << TAG


static inline QString formatTime(int64_t timestamp){
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
    return dateTime.toString("MM-dd HH:mm:ss");
}

// 获取时间戳 s
static inline int64_t getTime(){
    return QDateTime::currentSecsSinceEpoch();
}

// 根据QByteArray转成QIcon
static inline QIcon makeIcon(const QByteArray& byteArray){
    QPixmap pixmap;
    pixmap.loadFromData(byteArray);
    QIcon icon(pixmap);
    return icon;
}

// 读写文件操作
//  从指定文件中读取所以二进制内容，得到一个QBytearray
static inline QByteArray loadFileToByteArray(const QString& path){
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if(!ok){
        LOG() << "文件打开失败";
        return QByteArray();
    }
    QByteArray content = file.readAll();
    file.close();
    return content;
}

// 吧QByteArray内容，写入到文件
static inline void writeByteArrayToFile(const QString& path, const QByteArray& content){
    QFile file(path);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok){
        LOG() << "打开文件失败";
        return;
    }
    file.write(content);
    file.flush();
    file.close();
}

/**
*用户信息
*/
class UserInfo{
public:
    QString userId = "";        // 用户编号
    QString nickname = "";      // 用户昵称
    QString description = "";   // 用户签名
    QString phone = "";         // 手机号
    QIcon avatar;               // 用户头像

    // 从 protobuffer 的 UserInfo 对象, 转成当前代码的 UserInfo 对象
    void load(const bite_im::UserInfo& userInfo) {
        this->userId = userInfo.userId();
        this->nickname = userInfo.nickname();
        this->phone = userInfo.phone();
        this->description = userInfo.description();
        if (userInfo.avatar().isEmpty()) {
            // 使用默认头像即可
            this->avatar = QIcon(":/resource/image/defaultAvatar.png");
        } else {
            this->avatar = makeIcon(userInfo.avatar());
        }
    }
};

/**
*消息信息
*/
enum MessageType{
    TEXT_TYPE,  // 文本消息
    IMAGE_TYPE,  // 图片消息
    FILE_TYPE,  // 文件消息
    SPEECH_TYPE  // 语音消息
};

// 信息构建，采用工厂设计模式
class Message{
public:
    QString messageId = "";                 // 消息编号
    QString chatSessionId = "";             // 消息所属会话id
    QString time = "";                      // 消息时间
    MessageType messageType = TEXT_TYPE;    // 消息类型
    UserInfo sender;                        // 发送者信息
    QByteArray content;                     // 消息正文内容
    QString fileId = "";                    // 文件的身份标识，为文件、语音、图片时有效
    QString fileName = "";                  // 文件名称，类型为文件 有效

    // 此处extraInfo 目前只是在消息类型为文件消息时，作为“文件名"补充
    static Message makeMessage(MessageType messageType, const QString& chatSessionId,
                                const UserInfo& sender, const QByteArray& content,
                               const QString extraInfo){
        if(messageType == TEXT_TYPE){
            return makeTextMessage(chatSessionId, sender, content);
        }
        else if(messageType == IMAGE_TYPE){
            return makeImageMessage(chatSessionId, sender, content);
        }
        else if(messageType == FILE_TYPE){
            return makeFileMessage(chatSessionId, sender, content, extraInfo);
        }
        else if(messageType == SPEECH_TYPE){
            return makeSpeechMessage(chatSessionId, sender, content);
        }
        else{
            // 未知信息类型
            return Message();
        }
    }


    void load(const bite_im::MessageInfo& messageInfo) {
        this->messageId = messageInfo.messageId();
        this->chatSessionId = messageInfo.chatSessionId();
        this->time = formatTime(messageInfo.timestamp());
        this->sender.load(messageInfo.sender());

        // 设置消息类型
        auto type = messageInfo.message().messageType();
        if (type == bite_im::MessageTypeGadget::MessageType::STRING) {
            this->messageType = TEXT_TYPE;
            this->content = messageInfo.message().stringMessage().content().toUtf8();
        } else if (type == bite_im::MessageTypeGadget::MessageType::IMAGE) {
            this->messageType = IMAGE_TYPE;
            if (messageInfo.message().imageMessage().hasImageContent()) {
                this->content = messageInfo.message().imageMessage().imageContent();
            }
            if (messageInfo.message().imageMessage().hasFileId()) {
                this->fileId = messageInfo.message().imageMessage().fileId();
            }
        } else if (type == bite_im::MessageTypeGadget::MessageType::FILE) {
            this->messageType = FILE_TYPE;
            if (messageInfo.message().fileMessage().hasFileContents()) {
                this->content = messageInfo.message().fileMessage().fileContents();
            }
            if (messageInfo.message().fileMessage().hasFileId()) {
                this->fileId = messageInfo.message().fileMessage().fileId();
            }
            this->fileName = messageInfo.message().fileMessage().fileName();
        } else if (type == bite_im::MessageTypeGadget::MessageType::SPEECH) {
            this->messageType = SPEECH_TYPE;
            if (messageInfo.message().speechMessage().hasFileContents()) {
                this->content = messageInfo.message().speechMessage().fileContents();
            }
            if (messageInfo.message().speechMessage().hasFileId()) {
                this->fileId = messageInfo.message().speechMessage().fileId();
            }
        } else {
            // 错误的类型, 啥都不做了, 只是打印一个日志
            LOG() << "非法的消息类型! type=" << type;
        }
    }

private:
    // 用于生成唯一的messageId
    static QString makeId(){
        return "M" + QUuid::createUuid().toString().sliced(25, 12);
    }
    static Message makeTextMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray& content){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());  // 生成一个格式化时间
        message.content = content;
        message.messageType = TEXT_TYPE;
        // 对于文本消息来说，这两属性不使用
        message.fileId = "";
        message.fileName = "";

        return message;
    }
    static Message makeImageMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray& content){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());  // 生成一个格式化时间
        message.content = content;
        message.messageType = IMAGE_TYPE;

        message.fileId = "";
        // 对于图片消息来说，改属性不使用
        message.fileName = "";

        return message;
    }
    static Message makeFileMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray& content, const QString& fileName){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());  // 生成一个格式化时间
        message.content = content;
        message.messageType = FILE_TYPE;

        message.fileId = "";
        message.fileName = fileName;

        return message;
    }
    static Message makeSpeechMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray& content){
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());  // 生成一个格式化时间
        message.content = content;
        message.messageType = SPEECH_TYPE;
        message.fileId = "";
        // 不使用
        message.fileName = "";

        return message;
    }
};

/**
*会话信息
*/
class ChatSessionInfo{
public:
    QString chatSessionId = "";     // 会话Id
    QString chatSessionName = "";   // 会话名字,单聊或群聊名字
    Message lastMessage;             // 最新一条消息显示效果
    QIcon avatar;                   // 单聊或群聊的头像
    QString userId = "";
    QString owner_id = "";


    void load(const bite_im::ChatSessionInfo& chatSessionInfo) {
        this->chatSessionId = chatSessionInfo.chatSessionId();
        this->chatSessionName = chatSessionInfo.chatSessionName();
        this->owner_id = chatSessionInfo.ownerId();
        if (chatSessionInfo.hasSingleChatFriendId()) {
            this->userId = chatSessionInfo.singleChatFriendId();
        }
        if (chatSessionInfo.hasPrevMessage()) {
            lastMessage.load(chatSessionInfo.prevMessage());
        }
        if (chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty()) {
            // 已经有头像了, 直接设置这个头像
            this->avatar = makeIcon(chatSessionInfo.avatar());
        } else {
            // 如果没有头像, 则根据当前会话是单聊还是群聊, 使用不同的默认头像.
            if (userId != "") {
                // 单聊
                this->avatar = QIcon(":/resource/image/defaultAvatar.png");
            } else {
                // 群聊
                this->avatar = QIcon(":/resource/image/groupAvatar.png");
            }
        }
    }
};

} // end model
